package com.paydemo.pay.RabbitMQ;

import com.alibaba.fastjson.JSON;
import com.paydemo.pay.entity.PayOrder;
import com.paydemo.pay.service.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;

/**
 * 支付消息消费者
 */
@Slf4j
@Component
public class PaymentMQConsumer {

    @Resource
    private PayOrderService payOrderService;

    /**
     * 处理订单创建消息
     */
    @RabbitListener(queues = MqConstants.PAYMENT_ORDER_CREATE_QUEUE)
    public void handleOrderCreateMessage(PaymentMessage message) {
        log.info("接收到订单创建消息：{}", JSON.toJSONString(message));
        try {
            // 异步处理订单创建后的业务逻辑
            CompletableFuture.runAsync(() -> {
                try {
                    // 记录订单创建日志
                    log.info("异步记录订单创建日志，订单号：{}", message.getOrderNo());
                    
                    // 发送订单创建通知
                    sendOrderCreateNotification(message);
                    
                    // 其他异步处理逻辑
                    log.info("订单创建消息处理成功，订单号：{}", message.getOrderNo());
                } catch (Exception e) {
                    log.error("异步处理订单创建消息异常，订单号：{}，错误：{}", message.getOrderNo(), e.getMessage(), e);
                    throw new RuntimeException("异步处理订单创建消息异常", e);
                }
            });
        } catch (Exception e) {
            log.error("订单创建消息处理失败，订单号：{}，错误：{}", message.getOrderNo(), e.getMessage(), e);
            // 这里不需要手动抛出异常，因为我们使用了AUTO模式，Spring会自动处理重试和死信队列
            throw new RuntimeException("订单创建消息处理失败", e);
        }
    }

    /**
     * 处理支付成功消息
     */
    @RabbitListener(queues = MqConstants.PAYMENT_SUCCESS_QUEUE)
    public void handlePaymentSuccessMessage(PaymentMessage message) {
        log.info("接收到支付成功消息：{}", JSON.toJSONString(message));
        try {
            // 查询订单信息
            String orderNo = message.getOrderNo();
            PayOrder payOrder = payOrderService.getByOrderNo(orderNo);
            
            if (payOrder != null) {
                // 异步处理支付成功后的业务逻辑
                CompletableFuture.runAsync(() -> {
                    try {
                        // 发送支付成功短信通知
                        sendPaymentSuccessSMS(payOrder);
                        
                        // 发送支付成功邮件通知
                        sendPaymentSuccessEmail(payOrder);
                        
                        // 更新订单相关统计数据
                        updateOrderStatistics(payOrder);
                        
                        // 触发后续业务流程
                        triggerNextBusinessProcess(payOrder);
                        
                        log.info("支付成功消息处理成功，订单号：{}", orderNo);
                    } catch (Exception e) {
                        log.error("异步处理支付成功消息异常，订单号：{}，错误：{}", orderNo, e.getMessage(), e);
                        throw new RuntimeException("异步处理支付成功消息异常", e);
                    }
                });
            } else {
                log.warn("未找到订单信息，订单号：{}", orderNo);
                throw new RuntimeException("未找到订单信息");
            }
        } catch (Exception e) {
            log.error("支付成功消息处理失败，订单号：{}，错误：{}", message.getOrderNo(), e.getMessage(), e);
            throw new RuntimeException("支付成功消息处理失败", e);
        }
    }

    /**
     * 处理支付失败消息
     */
    @RabbitListener(queues = MqConstants.PAYMENT_FAIL_QUEUE)
    public void handlePaymentFailMessage(PaymentMessage message) {
        log.info("接收到支付失败消息：{}", JSON.toJSONString(message));
        try {
            // 查询订单信息
            String orderNo = message.getOrderNo();
            PayOrder payOrder = payOrderService.getByOrderNo(orderNo);
            
            if (payOrder != null) {
                // 异步处理支付失败后的业务逻辑
                CompletableFuture.runAsync(() -> {
                    try {
                        // 发送支付失败通知
                        sendPaymentFailNotification(payOrder);
                        
                        // 释放库存（如果有预占库存的话）
                        releaseInventory(payOrder);
                        
                        // 记录支付失败日志
                        log.info("记录支付失败日志，订单号：{}", orderNo);
                        
                        log.info("支付失败消息处理成功，订单号：{}", orderNo);
                    } catch (Exception e) {
                        log.error("异步处理支付失败消息异常，订单号：{}，错误：{}", orderNo, e.getMessage(), e);
                        throw new RuntimeException("异步处理支付失败消息异常", e);
                    }
                });
            } else {
                log.warn("未找到订单信息，订单号：{}", orderNo);
                throw new RuntimeException("未找到订单信息");
            }
        } catch (Exception e) {
            log.error("支付失败消息处理失败，订单号：{}，错误：{}", message.getOrderNo(), e.getMessage(), e);
            throw new RuntimeException("支付失败消息处理失败", e);
        }
    }

    /**
     * 处理支付超时消息
     */
    @RabbitListener(queues = MqConstants.PAYMENT_TIMEOUT_QUEUE)
    public void handlePaymentTimeoutMessage(PaymentMessage message) {
        log.info("接收到支付超时消息：{}", JSON.toJSONString(message));
        try {
            // 查询订单信息
            String orderNo = message.getOrderNo();
            PayOrder payOrder = payOrderService.getByOrderNo(orderNo);
            
            if (payOrder != null && payOrder.getPayStatus() == 0) {
                // 异步处理支付超时后的业务逻辑
                CompletableFuture.runAsync(() -> {
                    try {
                        // 更新订单状态为超时
                        payOrder.setPayStatus(3); // 支付超时
                        payOrderService.updateById(payOrder);
                        
                        // 发送支付超时通知
                        sendPaymentTimeoutNotification(payOrder);
                        
                        // 释放库存（如果有预占库存的话）
                        releaseInventory(payOrder);
                        
                        log.info("订单支付超时，已关闭，订单号：{}", orderNo);
                    } catch (Exception e) {
                        log.error("异步处理支付超时消息异常，订单号：{}，错误：{}", orderNo, e.getMessage(), e);
                        throw new RuntimeException("异步处理支付超时消息异常", e);
                    }
                });
            } else {
                log.info("订单已处理或不存在，忽略超时消息，订单号：{}", orderNo);
            }
        } catch (Exception e) {
            log.error("支付超时消息处理失败，订单号：{}，错误：{}", message.getOrderNo(), e.getMessage(), e);
            throw new RuntimeException("支付超时消息处理失败", e);
        }
    }
    
    /**
     * 发送订单创建通知
     */
    private void sendOrderCreateNotification(PaymentMessage message) {
        // 模拟发送订单创建通知
        log.info("发送订单创建通知，订单号：{}", message.getOrderNo());
        // 实际项目中可以调用短信服务、邮件服务等
    }
    
    /**
     * 发送支付成功短信通知
     */
    private void sendPaymentSuccessSMS(PayOrder payOrder) {
        // 模拟发送支付成功短信通知
        log.info("发送支付成功短信通知，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以调用短信服务
    }
    
    /**
     * 发送支付成功邮件通知
     */
    private void sendPaymentSuccessEmail(PayOrder payOrder) {
        // 模拟发送支付成功邮件通知
        log.info("发送支付成功邮件通知，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以调用邮件服务
    }
    
    /**
     * 更新订单相关统计数据
     */
    private void updateOrderStatistics(PayOrder payOrder) {
        // 模拟更新订单相关统计数据
        log.info("更新订单相关统计数据，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以更新销售额、交易量等统计数据
    }
    
    /**
     * 触发后续业务流程
     */
    private void triggerNextBusinessProcess(PayOrder payOrder) {
        // 模拟触发后续业务流程
        log.info("触发后续业务流程，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以触发发货流程、积分发放等
    }
    
    /**
     * 发送支付失败通知
     */
    private void sendPaymentFailNotification(PayOrder payOrder) {
        // 模拟发送支付失败通知
        log.info("发送支付失败通知，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以调用短信服务、邮件服务等
    }
    
    /**
     * 发送支付超时通知
     */
    private void sendPaymentTimeoutNotification(PayOrder payOrder) {
        // 模拟发送支付超时通知
        log.info("发送支付超时通知，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以调用短信服务、邮件服务等
    }
    
    /**
     * 释放库存
     */
    private void releaseInventory(PayOrder payOrder) {
        // 模拟释放库存
        log.info("释放库存，订单号：{}", payOrder.getOrderNo());
        // 实际项目中可以调用库存服务释放预占的库存
    }
} 